package com.wangshidai.controller;

import cn.hutool.core.bean.BeanUtil;
import com.wangshidai.entity.R;
import com.wangshidai.entity.SysDept;
import com.wangshidai.form.deptform.DeptSaveForm;
import com.wangshidai.form.deptform.DeptTreeForm;
import com.wangshidai.form.deptform.DeptUpdateForm;
import com.wangshidai.service.SysDeptService;
import com.wangshidai.util.BusinessException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Mr.fish
 * @create 2022-03-20 0:44
 */
@RestController
@RequestMapping("/api")
@Api(tags = "机构管理接口")
public class DeptController {
    @Autowired
    private SysDeptService deptService;

    /**
     * 树形列表显示所有部门信息，默认树形都是展开的
     *
     * @param
     * @return
     */
    @GetMapping("/department/parent")
    @ApiOperation("查询所有机构树形列表")
    public R searchName() {
        //准备数据显示的容器；这里面的元素都是根节点；所有的子节点都在根节点的children里面
        List<DeptTreeForm> deptTreeFormList = new ArrayList<>();
        //查询出所有的部门信息
        List<DeptTreeForm> deptTreeForms = deptService.queryAll();
        //建立一个map 将所有的数据放进去，提高查找效率 key为 id  value 为对象
        Map<Long, DeptTreeForm> deptTreeFormMap = new HashMap<>();
        for (DeptTreeForm deptTreeForm : deptTreeForms) {
            deptTreeFormMap.put(deptTreeForm.getId(), deptTreeForm);
        }
        //遍历所有部门信息，找到根节点和其所有子节点
        for (DeptTreeForm deptTreeForm : deptTreeForms) {
            //最开始，把每一个节点当做子节点，如果此节点的pid为0，则此节点为根节点，否则，他为其他节点的子节点。
            DeptTreeForm deptChild = deptTreeForm;
            //如果这个部门没有上级，则为顶级节点
            if (deptChild.getPid() == 0) {
                //将顶级节点加入到展示数据的容器中，他所有的孩子会在他的children属性中显示，孙子会在儿子的children中显示，以此类推
                deptTreeFormList.add(deptTreeForm);
            } else {//否则，有上级部门 ，以pid寻找父子关系，将儿子装进父亲的child集合中
                //找到该节点的父节点，此节点的pid即为父节点的id，以此找到 map中的key为pid，   value 即为父节点对象
                DeptTreeForm parentDept = deptTreeFormMap.get(deptChild.getPid());
                //将此节点添加到其父节点的children集合中
                parentDept.getChildren().add(deptChild);
            }
        }
        return new R(200, "查询成功", deptTreeFormList);
    }

    /**
     * 根据部门名称模糊查询，查询出符合条件的数据以及子节点数据
     *
     * @param searchName 部门名称
     * @return
     */
    @GetMapping("/department/list")
    @ApiOperation("根据部门名称模糊查询机构及其下级列表")
    public R searchName(@ApiParam(name="部门名称",value="传入要查询的部门名称字段，模糊查询",required=true)String searchName) {
        List<SysDept> deptList = deptService.listDept(searchName);
        //查询出所有的部门信息
        List<DeptTreeForm> deptTreeForms = deptService.queryAll();
        //准备数据显示的容器
        List<DeptTreeForm> deptTreeFormList = new ArrayList<>();
        //建立一个map 将所有的数据放进去，提高查找效率
        Map<Long, DeptTreeForm> deptTreeFormMap = new HashMap<>();
        for (DeptTreeForm deptTreeForm : deptTreeForms) {
            deptTreeFormMap.put(deptTreeForm.getId(), deptTreeForm);
        }
        //循环所有通过名称模糊查询出来的数据
        for (SysDept sysDept : deptList) {
            //将所有的数据在模糊查询出来的数据里面循环，目的是寻找子节点
            for (DeptTreeForm deptTreeForm : deptTreeForms) {
                // 跟树一样，还是最开始把所有的节点设置为子节点。
                DeptTreeForm deptChild = deptTreeForm;
                // 这里，如果有数据和模糊查询的数据的id相同，说明是同一个对象，那这个对象就是我们模糊查询出来的对象，把他当做根节点，加入到展示数据的集合中
                if (deptChild.getId() == sysDept.getId()) {
                    deptTreeFormList.add(deptChild);
                } else if (deptChild.getPid() != 0) {//否则，除了顶级节点之外，都通过pid寻找自己的父节点
                    //找到该节点的父节点，此节点的pid即为父节点的id，以此找到 map中的key为pid，   value 即为父节点对象
                    DeptTreeForm parentDept = deptTreeFormMap.get(deptChild.getPid());
                    // 找到父节点后，查看该父节点下的所有子节点，
                    List<DeptTreeForm> children = parentDept.getChildren();
                    // 查看子节点集合中是否已经包含了该节点，如果没有包含，说明是第一次加入，则在子节点集合中加入该子节点
                    if(!children.contains(deptChild)){
                        //将此节点添加到其父节点的children集合中
                        parentDept.getChildren().add(deptChild);
                    }
                }
            }
        }
        return new R(200, "查询成功", deptTreeFormList);
    }

    /**
     * 添加部门信息
     *
     * @param dept 装修改数据的对象，在此类中属性会有一些约束；此类的目的是避免实体类太过于臃肿。
     * @return
     * @throws BusinessException
     */
    @PostMapping("/department")
    @ApiOperation("添加部门：需要一个部门对象所有属性")
    public R saveDept(@ApiParam(name="部门对象",value="传入部门对象所有属性",required=true)DeptSaveForm dept) throws BusinessException {
        //创建一个新的sysDept对象，以便mybatisplus 使用
        SysDept sysDept = new SysDept();
        //将装修改数据的容器对象属性拷贝到 上面的对象中。
        BeanUtil.copyProperties(dept, sysDept);
        //方法内部调用mybatisplus 方法，完成添加部门信息
        deptService.saveDept(sysDept);
        return new R(200, "新增成功", null);
    }

    /**
     *
     * @param dept 用来装修改信息的容器，里面属性有一些非空等约束
     * @param id 修改部门的id
     * @return
     * @throws BusinessException
     */
    @PutMapping("/department/{id}")
    @ApiOperation("修改部门信息：需要一个部门对象所有属性")
    public R updateDept(@ApiParam(name="部门对象",value="传入部门对象所有属性",required=true) DeptUpdateForm dept, @PathVariable("id") @ApiParam(name="部门id",value="传入要修改的部门id",required=true)Integer id) throws BusinessException {
        //先根据id查询出部门信息
        SysDept sysDept = deptService.selectById(id);
        //将修改后的部门信息赋值给查询出来的部门
        BeanUtil.copyProperties(dept, sysDept);
        //方法内部调用mybatisplus 完成修改
        deptService.updateDept(sysDept);
        return new R(200, "编辑成功", null);
    }

    /**
     * 删除部门
     *
     * @param id 前端传过来的要删除的id
     * @return
     * @throws BusinessException
     */
    @DeleteMapping("/department/{id}")
    @ApiOperation("根据id删除部门信息")
    public R deleteDept(@ApiParam(name="部门id",value="传入要删除的部门id",required=true)@PathVariable Integer id) throws BusinessException {
        //方法内部调用mybatisplus 完成删除
        deptService.deleteDept(id);
        return new R(200, "删除成功", null);
    }

}
